/* How to Hook with Logos
Hooks are written with syntax similar to that of an Objective-C @implementation.
You don't need to #include <substrate.h>, it will be done automatically, as will
the generation of a class list and an automatic constructor.

%hook ClassName

// Hooking a class method
+ (id)sharedInstance {
	return %orig;
}

// Hooking an instance method with an argument.
- (void)messageName:(int)argument {
	%log; // Write a message about this call, including its class, name and arguments, to the system log.

	%orig; // Call through to the original function with its original arguments.
	%orig(nil); // Call through to the original function with a custom argument.

	// If you use %orig(), you MUST supply all arguments (except for self and _cmd, the automatically generated ones.)
}

// Hooking an instance method with no arguments.
- (id)noArguments {
	%log;
	id awesome = %orig;
	[awesome doSomethingElse];

	return awesome;
}

// Always make sure you clean up after yourself; Not doing so could have grave consequences!
%end
*/


#include "fishhook.h"
#import <dlfcn.h>


@interface SpringBoard
// 需要添加自定义方法的方法声明，否则编译不过
// 运行时会从%new添加的方法列表中查找方法
- (void)mm_handleMenuButtonDown;
- (void)mm_handleMenuLockButtonDown;
@end


static int (*orig_close)(int);
static int (*orig_open)(const char *, int, ...);

int my_close(int fd) {
    printf("Calling real close(%d)\n", fd);
    return orig_close(fd);
}

int my_open(const char *path, int oflag, ...) {
    va_list ap = {0};
    mode_t mode = 0;
    
    if ((oflag & O_CREAT) != 0) {
        // mode only applies to O_CREAT
        va_start(ap, oflag);
        mode = va_arg(ap, int);
        va_end(ap);
        printf("Calling real open('%s', %d, %d)\n", path, oflag, mode);
        return orig_open(path, oflag, mode);
    } else {
        printf("Calling real open('%s', %d)\n", path, oflag);
        return orig_open(path, oflag, mode);
    }
}


%hook SpringBoard

// 使用 %new 添加自定义的方法
%new
- (void)mm_handleMenuButtonDown {
	NSLog(@"mm_handleMenuButtonDown");
}

%new
- (void)mm_handleMenuLockButtonDown {
	NSLog(@"mm_handleMenuLockButtonDown");
}

-  (void)applicationDidFinishLaunching:(id)application 
{ 
    %orig; 
    UIAlertView *alert = [[UIAlertView alloc]  
    initWithTitle:@"Dream MAKE Dream！" 
    message:nil 
    delegate:self cancelButtonTitle:@"OK"
    otherButtonTitles:nil]; 
    [alert show];


    // fishfook use
    struct rebinding binds[2];
    // orig_close是一个函数指针，(void *)&orig_close 是一个返回参数，所以用取地址，(void *)&orig_open也是类似的
    struct rebinding bind1 = {"close", (void *)my_close, (void **)&orig_close};
    binds[0] = bind1;
    binds[1] = (struct rebinding){"open", (void *)my_open, (void **)&orig_open};

    // rebind_symbols((struct rebinding[2]){{"close", my_close, (void *)&orig_close}, {"open", my_open, (void *)&orig_open}}, 2);
    // 转换为：
    rebind_symbols(binds, 2);
    
    // Open our own binary and print out first 4 bytes (which is the same
    // for all Mach-O binaries on a given architecture)
    // int fd = open(argv[0], O_RDONLY);
    // uint32_t magic_number = 0;
    // read(fd, &magic_number, 4);
    // printf("Mach-O Magic Number: %x \n", magic_number);
    // close(fd);
}

- (void)menuButtonDown:(struct __GSEvent *)arg1 {
	%orig; 
	[self mm_handleMenuButtonDown];
}

- (void)_menuButtonDown:(struct __IOHIDEvent *)arg1 {
	%orig; 
	[self mm_handleMenuButtonDown];
}

- (void)headsetButtonDown:(struct __GSEvent *)arg1 {
	%orig; 
	NSLog(@"headsetButtonDown");
}

- (void)lockButtonDown:(struct __GSEvent *)arg1 {
	%orig;
	[self mm_handleMenuLockButtonDown];
}
%end
